package com.main;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;

import com.data.DrawObject;
import com.data.LineData;
import com.data.Point3D;
import com.data.Polygon3D;
import com.data.ZBuffer;
import com.editors.Editor;
import com.objects.Track;
import com.objects.Train;
import com.objects.Wagon;
import com.panels.EditTrainPanel;
import com.panels.ManageTrainPanel;
import com.panels.cell.ValuePair;


public class TrainFrame  extends Railway implements KeyListener, MenuListener {

	
	int BOTTOM_BORDER=100;
	int LEFT_BORDER=100;

	private JPanel center;
	private Graphics2D graphics2D;

	private BufferedImage buf=null;

	public int WIDTH=1000;
	public int HEIGHT=800;
	
	public int LOC_X=0;
	public int LOC_Y=0;

	public 	int x0=200;
	public 	int y0=200;
	
	private BufferedImage trackImage;
	int trackWidth=20;
	
	private JFileChooser fc;
	private File currentDirectory=null;
	private File currentFile=null;
	
	public BufferedImage[] worldImages=null;
	private BufferedImage[] objectImages;
	
    int VISUAL_MODE_ON_TRAIN=0;
    int VISUAL_MODE_GROUND=1;
    int VISUAL_MODE=VISUAL_MODE_ON_TRAIN;

	public static void main(String[] args) {

		TrainFrame wb=new TrainFrame();

		wb.start();


	}

	private void start() {

		initialize();

		Thread runner=new Thread(){



			public void run() {

				while(true){

					draw();

					try {

						Thread.sleep(150);
						t=t+dt;

					} catch (InterruptedException e) {

						e.printStackTrace();
					}

				}
			}

		};
		runner.start();
	}
	

	public void initialize() {

		super.initialize();
		
		try {
			trackImage=ImageIO.read(new File("lib/track.jpg"));
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		try {

			worldImages=Editor.loadImages();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		try {

			objectImages=Editor.loadObjectImages();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	

		graphics2D=(Graphics2D) center.getGraphics();

		buf=new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
		
		setLocations(WIDTH+LOC_X,LOC_Y);
	}


	private void draw() {

		dynamics();
		
		if(VISUAL_MODE==VISUAL_MODE_ON_TRAIN){
			x0=this.HEIGHT/2-(int) trains[0].wagons[0].getFrontCenter().x;
			y0=this.WIDTH/2-(int) trains[0].wagons[0].getFrontCenter().y;
		}
		else{
			
			
		}
		if(graphics2D==null)
			graphics2D=(Graphics2D) center.getGraphics();

		Graphics2D bufGraphics=(Graphics2D)buf.getGraphics();

		draw(bufGraphics);

		graphics2D.drawImage(buf,0,0,WIDTH,HEIGHT,null);

	}


	private void draw(Graphics2D bufGraphics) {

		bufGraphics.setColor(Color.BLACK);
		bufGraphics.fillRect(0,0,WIDTH,HEIGHT);

		if(landscape!=null){
			

			int sz=landscape.polygonData.size();

			for (int i = 0; i < sz; i++) {
				LineData ld = (LineData) landscape.polygonData.elementAt(i);

				Color color=ZBuffer.fromHexToColor(ld.getHexColor());

				drawPolygon(ld,landscape.points,bufGraphics,color);
			}
			
		}
		
		if(objects!=null){
			
			//here draw objects
			
			for (int i = 0; i < objects.size(); i++) {
				DrawObject dro = (DrawObject) objects.elementAt(i);
				
				
				int xx=(int) calcX(dro.x);
				int yy=(int) calcY(dro.x);
					
				bufGraphics.drawImage(objectImages[dro.getIndex()],xx,yy,null);
				
			}
			
		}

		bufGraphics.setColor(Color.CYAN);
		for (int j = 0; j < tracks.length; j++) {
			
			Track tr0=tracks[j];
			
			/*int xx0=calcX(tr0.start.x);
			int yy0=calcY(tr0.start.y);


			if(xx0>0 && xx0<WIDTH && yy0>0 && yy0<HEIGHT )
				bufGraphics.fillOval(xx0-2,yy0-2,5,5);
			
			Track tr1=tracks[(j+1)%numTracks];
			
			int xx1=calcX(tr1.start.x);
			int yy1=calcY(tr1.start.y);
			
			
			bufGraphics.drawLine(xx0,yy0,xx1,yy1); */  
			
			double orientation=-tr0.orientation;
			int length=(int)tr0.length;
			
			//bufGraphics.setColor(Color.BLACK);
			
			AffineTransform saveAT = bufGraphics.getTransform();
			bufGraphics.rotate(orientation,calcX(tr0.start.x),calcY(tr0.start.y));
			bufGraphics.drawImage(trackImage,calcX(tr0.start.x),calcY(tr0.start.y+trackWidth/2),length,trackWidth,null,null);
			bufGraphics.setTransform(saveAT);
		}
		
		

		for (int k = 0; k < trains.length; k++) {			

			Wagon[] wagons = trains[k].wagons;

			for (int i = 0; i < wagons.length; i++) {
				
				Wagon w=wagons[i];

				double sinf=Math.sin(wagons[i].fi);
				double cosf=Math.cos(wagons[i].fi);

				Point3D center_f=new Point3D(wagons[i].cm.x+wagons[i].semiLen*cosf,wagons[i].cm.y+wagons[i].semiLen*sinf,0);
				Point3D center_b=new Point3D(wagons[i].cm.x-wagons[i].semiLen*cosf,wagons[i].cm.y-wagons[i].semiLen*sinf,0);


				/*Point3D wheel_lf=new Point3D(center_f.x+wagons[i].semiWidth*sinf,center_f.y-wagons[i].semiWidth*cosf,0);
				Point3D wheel_rf=new Point3D(center_f.x-wagons[i].semiWidth*sinf,center_f.y+wagons[i].semiWidth*cosf,0);

				Point3D wheel_lb=new Point3D(center_b.x+wagons[i].semiWidth*sinf,center_b.y-wagons[i].semiWidth*cosf,0);
				Point3D wheel_rb=new Point3D(center_b.x-wagons[i].semiWidth*sinf,center_b.y+wagons[i].semiWidth*cosf,0);

				bufGraphics.setColor(Color.RED);
				drawLine(bufGraphics,center_f.x,center_f.y,center_b.x,center_b.y);
				bufGraphics.setColor(Color.GREEN);
				drawLine(bufGraphics,wheel_lf.x,wheel_lf.y,wheel_rf.x,wheel_rf.y);
				bufGraphics.setColor(Color.YELLOW);
				drawLine(bufGraphics,wheel_lb.x,wheel_lb.y,wheel_rb.x,wheel_rb.y);*/
				
				
				AffineTransform saveAT = bufGraphics.getTransform();
				bufGraphics.rotate(-w.fi,calcX(w.getBackCenter().x),calcY(w.getBackCenter().y));
				bufGraphics.drawImage(w.wagonImage,calcX(w.getBackCenter().x),calcY(w.getBackCenter().y+w.semiWidth),(int)(2*w.semiLen),(int)(w.semiWidth*2),null,null);
				bufGraphics.setTransform(saveAT);

			}

		}


	}	

	private void drawPolygon(LineData ld, Point3D[] points,
			Graphics2D bufGraphics, Color color) {
		

		bufGraphics.setColor(ZBuffer.fromHexToColor(ld.getHexColor()));
		
        Polygon3D pol = builProjectedPolygon(ld,points);
        
        Rectangle rect=pol.getBounds();
        
        bufGraphics.drawImage(worldImages[ld.getTexture_index()],rect.x,
				rect.y,
				(int)rect.getWidth(),
				(int)rect.getHeight(),
				null
        );
		
	}
	
	public Polygon3D builProjectedPolygon(LineData ld, Point3D[] points) {
		
		Polygon3D pol=new Polygon3D();
		
		int size=ld.size();


		for(int i=0;i<size;i++){


			int num=ld.getIndex(i);

			Point3D p=points[num];

			
			int xx=(int) calcX(p.x);
			int yy=(int) calcY(p.y);
			
			pol.addPoint(xx,yy);
			

		}
		
		return pol;
	}

	private int calcY(double y) {

		return HEIGHT- ((int) y+y0);
	}

	private int calcX(double x) {

		return (int)x+x0;
	}

	private void drawLine(Graphics2D bufGraphics, double x1, double y1, double x2, double y2) {

		bufGraphics.drawLine(calcX(x1),calcY(y1),calcX(x2),calcY(y2));

	}

	

	public TrainFrame(){

		
		setTitle("Train Frame");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(null);
		setSize(WIDTH+LEFT_BORDER,HEIGHT+BOTTOM_BORDER);

		center=new JPanel();			
		center.setBounds(0,0,WIDTH,HEIGHT);
		add(center);

		addKeyListener(this);
		

		setVisible(true);

	}


	public void loadTrain() {
		
		
		fc = new JFileChooser();
		fc.setDialogType(JFileChooser.SAVE_DIALOG);
		fc.setDialogTitle("Load train");
		if(currentDirectory!=null)
			fc.setCurrentDirectory(currentDirectory);
		if(currentFile!=null)
			fc.setSelectedFile(currentFile);
		
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = fc.getSelectedFile();
			
			currentDirectory=fc.getCurrentDirectory();
			currentFile=fc.getSelectedFile();
			loadTrain(file);

		} 
		
	}

	private void loadTrain(File file) {
		
		Vector vTrains=new Vector();
		
		try {
			BufferedReader br=new BufferedReader(new FileReader(file));

			String str=null;
			
			int counter=0;
			
			while((str=br.readLine())!=null){
				
			     str=str.substring(str.indexOf("=")+1);
			     
			     String[] vals = str.split(",");
			     
			     Train tr=new Train("Train_"+counter,vals.length,this);
			     
			     for (int i = 0; i < vals.length; i++) {
					
			    	 tr.wagons[i].wagon_type=Integer.parseInt(vals[i]);
			    	 
				}
				
			     vTrains.add(tr);
			     counter++;
			     
			}			
			
			br.close();
			
			removeTrains();
			
			trains=new Train[vTrains.size()];
			
			for (int i = 0; i < vTrains.size(); i++) {
				trains[i]  = (Train) vTrains.elementAt(i);
				putTrainOnTheRail(trains[i]);
			}
			setLocations(WIDTH+LOC_X,LOC_Y);
			
			draw();

		} catch (Exception e) {

			e.printStackTrace();
		}
		
		
	}

	
	private void removeTrains() {
		
		for (int i = 0; i < trains.length; i++) {
			
			trains[i].dispose();
		}
		
	}


	public void saveTrain() {
		
		
		fc = new JFileChooser();
		fc.setDialogType(JFileChooser.SAVE_DIALOG);
		fc.setDialogTitle("Save train");
		if(currentDirectory!=null)
			fc.setCurrentDirectory(currentDirectory);
		if(currentFile!=null)
			fc.setSelectedFile(currentFile);
		
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = fc.getSelectedFile();
			
			currentDirectory=fc.getCurrentDirectory();
			currentFile=fc.getSelectedFile();
			saveTrain(file);

		} 
		
	}

	private void saveTrain(File file) {
		
		
		PrintWriter pr;
		try {
			pr = new PrintWriter(new FileOutputStream(file));
			
			for (int i = 0; i < trains.length; i++) {
				
				Train train=trains[i];
				
				pr.print("TRAIN_"+i+"=");
				
				for (int j = 0; j < train.wagons.length; j++) {
					
					Wagon w = train.wagons[j];
					if(j>0)
						pr.print(",");
					pr.print(w.wagon_type);
					
					
					
				}
				pr.println();
				
			}

			pr.close(); 	

		} catch (FileNotFoundException e) {

			e.printStackTrace();
		}
		
	}

	@Override
	public void keyPressed(KeyEvent arg0) {

		int code=arg0.getKeyCode();

		if(code==KeyEvent.VK_ESCAPE){
			
			System.exit(0);
			
		}
		else if(code==KeyEvent.VK_T){
			
			openTrainPanel();
			
		}
		else if(code==KeyEvent.VK_1){
			
			setVISUAL_MODE(VISUAL_MODE_ON_TRAIN);
		}
		else if(code==KeyEvent.VK_2){
			
			setVISUAL_MODE(VISUAL_MODE_GROUND);
		}
		else if(code==KeyEvent.VK_LEFT){
			
			
			moveVisual(+1,0);
			
		}
		else if(code==KeyEvent.VK_RIGHT){
			
			
			moveVisual(-1,0);
			
		}
		else if(code==KeyEvent.VK_UP){
			
			
			moveVisual(0,-1);
		
		}
		else if(code==KeyEvent.VK_DOWN){
			
	
			 moveVisual(0,+1);
			
		}
		
	}
	private void moveVisual(int i, int j) {
		
		if(VISUAL_MODE==VISUAL_MODE_GROUND){
			
			x0+=5*i;
			y0+=5*j;
		}
		
	}

	private void moveVisual(int i) {
		// TODO Auto-generated method stub
		
	}

	private void openTrainPanel() {
		
		ManageTrainPanel mpt=new ManageTrainPanel(this);
		
	}
	
	public void buildEditTrain() {
		
		EditTrainPanel mpt=new EditTrainPanel(this);
		
        if(mpt.modified){
        	
        	for (int i = 0; i < mpt.cloned_trains.length; i++) {
				
        		trains[i].setTrainCode(mpt.cloned_trains[i].getTrainCode());
        		trains[i].wagons=mpt.cloned_trains[i].wagons;
        		
			}
        	
        }
		
		 
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}
	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void menuCanceled(MenuEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void menuDeselected(MenuEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void menuSelected(MenuEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public int getVISUAL_MODE() {
		return VISUAL_MODE;
	}

	public void setVISUAL_MODE(int vISUAL_MODE) {
		VISUAL_MODE = vISUAL_MODE;
	}




}
